雖然在DAY 3的時候已經介紹過路由的一些基本規範,當時我們知道ASP .NET MVC 是藉由路由(Route)規範方式將URL模式連結到Controller,且網址路由是定義在「App_Start」資料夾中的「RouteConfig.cs」檔案裡。但當時沒有說明太多,今天我們再稍微深入探討相關內容。
我們先重提一下原本預設的路由規則,如下Code:
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
這個路由規則的名稱name叫做Default,url的規則是Domain/控制器名稱/動作方法名稱/id參數值,輸入的網址會依此連到程式對應的控制器與動作方法。defaults則規定了當url沒有輸入控制器名稱,預設會連到HomeController;當url少了動作方法名稱,預設會連到Index()動作方法;當url沒有id參數時沒關係,因為預設為UrlParameter.Optional,代表參數可有可無。
由上述規則得知,當輸入的網址如果是:
https://localhost:44334/Home/Index
https://localhost:44334/Home/
https://localhost:44334/
都會連結到HomeController底下的Index()動作方法。
事實上路由規則可以有不只一組,比如下方Code,我在預設路由規則上面添加了一組新的路由規則,那麼會發生什麼事情呢?
            routes.MapRoute(
                name: "Test",
                url: "Index123/{controller}/{action}",
                defaults: new { controller = "Home", action = "Index" }
            );
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
首先路由規則比對的順序是由上而下,因此輸入的url會優先比對Test這組規則,如果比對後無法符合該規則,會繼續比對下一組,也就是Default。因此假如輸入的網址如果是:https://localhost:44334/Index123/Home/Login,它一樣會去執行HomeController底下的Login()方法。同樣道理,當網址為:
https://localhost:44334/Index123/Home/Index
https://localhost:44334/Index123/Home
https://localhost:44334/Index123/
同樣會連結到HomeController底下的Index()動作方法。
路由規則可以加上constraints來設定條件約束,直接舉下方Code例子來說明,比方說網址列如果有id參數的話,我們除了在動作方法將它的型別設為int以外,又希望要求輸入的值應該要是正數(>0)的話可以怎麼做呢?
    public class TestController : Controller
    {
        // GET: Test
        public ActionResult ShowContent(int id)
        {
            return Content($"會員編號是: {id}");
        }
    }
針對這樣的條件需求,我們可以在路由規則上增加constraints來限制條件,如下寫法:
            routes.MapRoute(
                name: "Test",
                url: "Test/{id}",
                defaults: new { controller = "Test", action = "ShowContent" }, 
                constraints: new { id = @"\d+" }
            );
這邊利用了正規表達式(Regular Expression)來限制id參數必須為一或多個0-9整數組合的值,當id輸入負數時會顯示下圖錯誤:
除了在RouteConfig.cs設定路由規則以外,在控制器與動作方法上新增Route Attribute是另外一種限制路由的方式,要啟用屬性路由的話,必須先在RouteConfig.cs新增如下Code:
routes.MapMvcAttributeRoutes();
而且新增的位置必須於所有路由規則之前,如下圖所示:
加入後就可以在控制器上方增加[RoutePrefix()]屬性,以及在動作方法上增加[Route()]屬性。
上圖所示的[RoutePrefix("Main")]屬性表示必須有該路由前綴才能夠進入該控制器,而不是依照原本的Home。
搭配[Route()]與[Route("Index")]表示要進入該動作方法的路由只能是Index或不加也可以。因此能夠進入此方法的url就只能是:
https://localhost:44334/Main/Index
https://localhost:44334/Main/
而以下原本的url皆無法進入:
https://localhost:44334/Home/Index
https://localhost:44334/Home/
https://localhost:44334/
最後稍微講一下在RouteConfig.cs最上面一行有個
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
這行意思是當路由格式為{resource}.axd/{*pathInfo}的情形下,會忽略路由比對。主要是方便相容Webform頁面可以並存於MVC專案內,詳細可以參考以下文章內容:
MVC專案routes.IgnoreRoute的實際用途
今天比較詳細探討路由的觀念,其實相關資料我也是上網查了許多才比較清楚一點,如果有說明不正確或不完整的地方,再麻煩大神們指教了~